#include "head.h"
#include "cc9d_support.h"
#include "adc.h"
#include "App_adc.h"
#include <stdio.h>


#define LOCAL_PORT AdcApp_PORT

/*************************************
 * 每5秒钟采集一次ADC值，如果ADC值发生了大于15的变化，则发送一个包，报告ADC值。
 * 每5分钟发送一次心跳包，报告ADC值。
 * 每10分钟储存一个值到RAM中。
 */
static uint32 sec_ticks = 0;//1s计数

static uint16 remote_addr = 0x0000; //远程地址
static uint8 to_port = 32; //目标端口

static uint16 adc_report_threshold = 16;//ADC值变化的阈值，超过此值则发送一个包报告ADC值。

static const uint16 Adc_interval = 5;//ADC报告的时间间隔，5s
static const uint16 Hart_beat_interval = 300;//心跳包的时间间隔，5min
static const uint16 Store_interval = 120;

//24小时 = 24*60 = 1440分钟，保证能够储存24小时的数据，所以每2分钟储存一个数据。



//储存ADC值到RAM中的结构体，每10分钟储存一个
typedef struct {
    uint16 adc_value;
    uint16 sno;
}sAdcRecord;
#define RECORD_LEN 2048
static sAdcRecord adc_records[RECORD_LEN];
//储存ADC值的索引，每储存一个值，索引加1，到索引上限后再次循环。
static int adc_record_index = 0;
//最后一次记录ADC的时间ms值，
static int last_store_sec_ticks = 0;
//记录的序号，每次记录加1，到上限后再次循环。
static uint16 record_sno = 0;
static void storeAdc(uint16 adc_value){
	last_store_sec_ticks = sec_ticks;
    adc_records[adc_record_index].adc_value = adc_value;
    adc_records[adc_record_index].sno = record_sno;
    adc_record_index++;
    adc_record_index %= RECORD_LEN;
    record_sno++;
    printf("T= %ds, store adc %x, sno %d\n", sec_ticks, adc_value, record_sno);
}
//获取某个序号对应的索引
static int getRecord(uint16 target){
    int distance = record_sno - target;//通常target较小，所以distance为正数
    //如果record_sno可能溢出，既0xffff+1 = 0,
    //这种情况会造成distance为负数，所以需要修正
    if (distance < 0) {
        distance += 0x10000;
    }
    if(distance >= RECORD_LEN){
        return -1;
    }
    int index = adc_record_index - distance;
    if (index < 0){
        index += RECORD_LEN;
    }    
    if (adc_records[index].sno != target){
        printf("getRecord error, target %d, index %d, sno %d\n", target, index, adc_records[index].sno);
        return -1;
    }else{
        return index;
    }
}

static void getHistory(sCc9dPkg* recv_pkg, uint8 data_len) {    //获取历史数据
    //第一步，解析参数
    struct {//将收到的数据按照结构体理解
        uint16 sno;//从哪个SNO开始
        uint8 num;//要获取多少个数据，负数表示从sno往前数
    }*arguments = (void*)(recv_pkg->datas + 1);
    uint16 sno;
    int num;
    if (data_len == 4) {
        sno = arguments->sno;
        num = arguments->num;
        if (num > 30) {
            num = 30;
        }
    } else if (data_len == 3) {
        sno = arguments->sno;
        num = 0;
    } else {
        printf("get data error, data_len = %d\n", data_len);
        return;
    }
    printf("get sno %d, num %d\n", sno, num);

    //第二步，准备发送包
    sCc9dPkg send_pkg;
    int send_len = 0;
    createResponsePkg(&send_pkg, recv_pkg);

    //第三步，填充数据的SNO
    *((uint16*)(send_pkg.datas)) = arguments->sno;//第一组数据是SNO
    send_len += 2;
    //第四步，填充后续的数据
    int count = 0;
    int index = getRecord(arguments->sno);
    while (index != -1) {
        ((uint16*)(send_pkg.datas + 2))[count] = adc_records[index].adc_value;
        send_len += 2;
        sno--;
        count++;
        if (count >= num) {
            break;
        }
        index = getRecord(sno);
    }
    //第五步，发送包
    cc9d_SendPkg(&send_pkg, send_len);
}




static void sendAdcPkg(uint16 adc_value) {
    sCc9dPkg send_pkg;
    send_pkg.from_port = LOCAL_PORT;
    send_pkg.to_port = to_port;
    send_pkg.remote_addr = remote_addr;
    send_pkg.datas[0] = (adc_value >> 0) & 0xff;
    send_pkg.datas[1] = (adc_value >> 8) & 0xff;
    cc9d_SendPkg(&send_pkg, 2);
}

void AdcApp_recvPkg(sCc9dPkg* recv_pkg, uint8 data_len) {
    if (data_len == 0) {
        return;
    }
    uint8 cmd = recv_pkg->datas[0]; 
    if(cmd == 'r'){//read_adc发送r立即读取一个ADC值
        uint16 adc_value = Adc_getValue(0);
        sCc9dPkg send_pkg;
        createResponsePkg(&send_pkg, recv_pkg);
        send_pkg.datas[0] = (adc_value >> 0) & 0xff;
        send_pkg.datas[1] = (adc_value >> 8) & 0xff;
        cc9d_SendPkg(&send_pkg, 2);
    }else if(cmd == 'c'){//获取最新记录的编号和时间
        sCc9dPkg send_pkg;
        createResponsePkg(&send_pkg, recv_pkg);
        *((uint32*)(send_pkg.datas)) = last_store_sec_ticks;
        *((uint16*)(send_pkg.datas + 4)) = record_sno;
        cc9d_SendPkg(&send_pkg, 6);
    }else if(cmd == 'h'){
        getHistory(recv_pkg, data_len);
    } else if (cmd == 't') {//获取最新记录的编号和时间
        sCc9dPkg send_pkg;
        createResponsePkg(&send_pkg, recv_pkg);
        *((uint32*)(send_pkg.datas)) = sec_ticks;
        cc9d_SendPkg(&send_pkg, 4);
    }
}


static void secTick(void) {
    static uint16 last_adc_value = 0x8000;//上一次的ADC值
    static uint16 timer_hart_beat = 0;//心跳包计时器
    static uint16 timer_store = 0;//储存计时器   
    timer_hart_beat++;
    timer_store++; 
    if (sec_ticks % Adc_interval == 0) {
        uint16 adc_value = Adc_getValue(0);
        int32 diff = adc_value - last_adc_value;
        if ((diff > adc_report_threshold)
            || (diff < -adc_report_threshold)
            || (timer_hart_beat >= Hart_beat_interval)
            ) {
            sendAdcPkg(adc_value);
            last_adc_value = adc_value;
            timer_hart_beat = 0;
        }
        if (timer_store>=Store_interval){
            timer_store -= Store_interval;
            storeAdc(adc_value);
        }
    }
}
void AdcApp_msTick(void) {
    static uint16 ms_ticks = 0;
    ms_ticks++;
    if (ms_ticks < 1000){
        return;
    } else{
        ms_ticks-=1000;
        sec_ticks++;
		secTick();
    }
}

void AdcApp_init(){
    Adc_init();
}

